#include <kernel/definiciones.h>
#include <kernel/system.h>
#include <kernel/system_asm.h>
#include <kernel/puertos.h>
#include <kernel/syscall.h>
#include <kernel/pcb.h>
#include <kernel/gdt.h>
#include <kernel/libk/string.h>
#include <kernel/libk/libk.h>

#include <kernel/mem/mem_part_kernel.h>
#include <kernel/mem/mem_part_firstfit.h>
#include <kernel/mem/paginas.h>

#include <shell/shell.h>
#include <shell/teclado.h>
#include <shell/sys_video.h>
#include <video.h>

#include <shell/cmd_log.h>
#include <shell/cmd_lotes.h>
#include <shell/cmd_planif.h>
#include <shell/cmd_regs.h>
#include <fs/ramfs.h>
#include <fs/fat.h>

#include <shell/help.h>
// Agregado - Mario
#include <kernel/shutdown.h> 

#include <kernel/drivers/floppy.h>  //niko

int iAutoCompletarCancelado = 0;

extern int iCantidadCaracteres;
extern int bActivarTeclado;
extern stuTSS stuTSSTablaTareas[CANTMAXPROCS];
extern stuPCB pstuPCB[CANTMAXPROCS];
extern int iFnSistema();
extern int iFnProceso1();

extern dword pdwGDT;
extern stuEstructuraGdt *pstuTablaGdt;
extern int uiUltimoPid;

extern void apagala();
//niko
extern struct stuFsHandleFat *pstuFsFatHandleHandle;
extern void vFnBorrarCaracter(int hwnd);
extern void vFnCambiarVisibilidadVentanaProceso();
extern unsigned int uiTamanioMemoriaBaja;
extern unsigned int uiTamanioMemoriaBios;
extern unsigned int uiUnidadBoot;
extern unsigned int uiTamanioBSS;
extern unsigned int uiTamanioKernel;
extern unsigned int uiModoMemoria;
extern stuVentana pstuVentana[HWND_VENTANA_MAX];
extern int iMatrizMf[30][2];
extern int iTamanioPagina;

extern semaforo semaforosEnElSistema[CANTMAXSEM];
extern shMem memoriasCompartidas[CANTMAXSHM];
void vFnInicializarEnv();
void vFnInicializarPath();
int cCaracterDevuelto = 13;	//devuelve el caracter tocado luego del autocompletar


char *Buffer[512];
char *stCmdTemp[512]; // Variable temporal del comando
char *stCmd[512]; // Variable donde se guarda el comando ingresado por el usuario

/**
\fn int iFnEsCmdShell(char *stComando)
\brief Busca en el buffer de cCaracteres la existencia del comando pasado como parÃ¡metro

\param stComando Puntero a cCaracter a una cadena de texto que contiene el nombre del comando buscado.
\return Integer que indica la posicion inicial en el buffer donde se encontro el comando o -1 si no lo encontrÃ³.
\date 09/04/2006
*/
int iFnEsCmdShell(char *stComando)
{
	int iN = 0, iJ = 0, iK = 0, iPosEncontrado = -1, iNroFaltantes;

	if (iCantidadCaracteres > 0) {
		while (((stBufferShell[iN] == ' ') || (stBufferShell[iN] == '\t')) && iN < TAMANIO_BUFFER_SHELL)	//busco el primer cCaracter
			//no-blanco,
		{		//tÃ­picamente es el primer cCaracter, pero
			iN++;	//lo buscamos igual en caso que hayan espacios o
		}		//tabulaciones antes del comando a interpretar

		if (iN < TAMANIO_BUFFER_SHELL)	//si iN==TAMANIO_BUFFER_SHELL, no hay ningun comando para interpretar.
			//Se llegÃ³ al final del buffer y todos los cCaracteres eran
			//blancos
		{
			iPosEncontrado = iN;
			while ((stComando[iJ] != ' ')
			       && (stComando[iJ] != '\0')
			       && (stBufferShell[iN] != ' ')
			       && (stBufferShell[iN] != '\t')
			       && (stBufferShell[iN] != '\0')
			       && (iPosEncontrado != -1)) {
				if (stComando[iJ] != stBufferShell[iN])
					iPosEncontrado = -1;
				iN++;
				iJ++;
			}
		}
//si no hubo errores de concordancia pero tampoco se llego a evaluar toda la
//longitud del comando pasado como parametro, completaremos el buffer con el.
		if (iPosEncontrado != -1 && stComando[iJ] != '\0') {
			//encuentro la cantidad de cCaracteres que faltan agregar
			for (iNroFaltantes = 0;
			     stComando[iJ] != '\0'; iJ++, iNroFaltantes++);

			//incremento la cantidad de cCaracteres declarados en el buffer a la nueva
			//cantidad.
			iCantidadCaracteres += iNroFaltantes;

			// desplazo los parametros hacia la derecha nrofaltantes posiciones.
			for (iK = iCantidadCaracteres;
			     (iK - iNroFaltantes) >= iN; iK--)
				stBufferShell[iK] =
				    stBufferShell[iK - iNroFaltantes];

			//vuelvo a iJ a su valor original para rellenar cn el resto del comando...
			iJ -= iNroFaltantes;

			for (; iNroFaltantes > 0;
			     iNroFaltantes--, iN++, iJ++) {
				stBufferShell[iN] = stComando[iJ];
			}
			for (iN = 0;
			     iN <
			     (iCantidadCaracteres +
			      iFnLongitudCadena(STRPROMPTLINE)); iN++)
				vFnBorrarCaracter(0);

			vFnImprimirPrompt();
			vFnImprimir("%s", stBufferShell);
			cCaracterDevuelto = cFnGetChar();
			if (cCaracterDevuelto != 13) {
				iAutoCompletarCancelado = 1;
				return (-1);
			}
		}
	}

	return iPosEncontrado;

}


/**
\fn int vFnObtenerCmd(char *stComando)
\brief Busca en el buffer de cCaracteres al comando

\param stComando Puntero a cCaracter a una cadena de texto que contiene el nombre del comando buscado.
\return Void no hace falta reportar nada.
\date 23/05/2009
*/
void vFnObtenerCmd(char *stComando, int *iArgumento)
{

	int iN = 0, iJ = 0, iK = 0;

	if (iCantidadCaracteres > 0) {
		while (((stBufferShell[iN] == ' ') || (stBufferShell[iN] == '\t')) && iN < TAMANIO_BUFFER_SHELL)	//busco el primer cCaracter
			//no-blanco,
		{		//tÃ­picamente es el primer cCaracter, pero
			iN++;	//lo buscamos igual en caso que hayan espacios o
		}		//tabulaciones antes del comando a interpretar

		if (iN < TAMANIO_BUFFER_SHELL)	//si iN==TAMANIO_BUFFER_SHELL, no hay ningun comando para interpretar.
			//Se llegÃ³ al final del buffer y todos los cCaracteres eran
			//blancos
		{
			while ((stBufferShell[iN] != ' ')
			       && (stBufferShell[iN] != '\t')
			       && (stBufferShell[iN] != '\0'))
                        {
				
			       stComando[iJ] = stBufferShell[iN];
				iN++;
				iJ++;
			}
                    stComando[iJ] = '\0';
		}
           iN++;
           if (((int)stBufferShell[iN] >= 48) && ((int)stBufferShell[iN] <= 51))  *iArgumento = (int)stBufferShell[iN] - 48 ;
           else *iArgumento = 3;
	}

	return 1;

}



/**
  \fn int iFnGetArg(int iPos, int iNumero, char *stResultado, int iAnchoMaximo)
  \brief Entrega el parÃ¡metro requerido de la lÃ­nea de comando.
  \param iPos La primer posiciÃ³n en el buffer desde donde comenzar a buscar.
  \param iNumero El numero de parÃ¡metro que se solicita del buffer de entrada.
  \param stResultado Un puntero a cadena conde copiarÃ¡ el parÃ¡metro recuperado
  \param iAnchoMaximo Un entero que le indica la longitud mÃ¡xima de la cadena que recibir el parÃ¡metro
  \return Entero que indica:
                1 si encontrÃ³ el parÃ¡metro
                2 si lo encontrÃ³ pero no pudo recuperarlo en su totalidad
                0 si no lo encontrÃ³.
  \date 09/04/2006
*/
int iFnGetArg(int iPos, int iNumero, char *stResultado, int iAnchoMaximo)
{
	int iN = iPos, iJ = 0, iK = 0;

	while (stBufferShell[iN] != '\0' && iJ < iNumero) {
		if ((stBufferShell[iN] == ' ')
		    && (stBufferShell[iN + 1] != ' '))
			iJ++;

		iN++;
	}

	if (iJ == iNumero)	//si se encontrÃ³ el parametro buscado lo copio
	{
		do {
			stResultado[iK] = stBufferShell[iK + iN];
			iK++;
		}
		while (iK < (iAnchoMaximo - 1)
		       && stBufferShell[iK + iN] != ' '
		       && (iK + iN) < iCantidadCaracteres);

		stResultado[iK] = '\0';

		//vFnImprimir("\ngetarg: nro %d, $%s$",iNumero,chrResultado);
		if (iK < (iAnchoMaximo - 1)) {
			return (1);
		} else {
			vFnImprimir("\ngetArg():El tamanio es invalido.");
			return (2);
		}
	} else {
		vFnImprimir("\ngetArg():parametro no encontrado.");
		return (0);
	}
}

int iFnGetArg2(int iPos, int iNumero, char *stResultado, int iAnchoMaximo)
{
	int iN = iPos, iJ = 0, iK = 0;

	while (stBufferShell[iN] != '\0' && iJ < iNumero) {
		if ((stBufferShell[iN] == ' ')
		    && (stBufferShell[iN + 1] != ' '))
			iJ++;

		iN++;
	}

	if (iJ == iNumero)	//si se encontrÃ³ el parametro buscado lo copio
	{
		do {
			stResultado[iK] = stBufferShell[iK + iN];
			iK++;
		}
		while (iK < (iAnchoMaximo - 1)
		       && stBufferShell[iK + iN] != '\0'
		       && (iK + iN) < iCantidadCaracteres);

		stResultado[iK] = '\0';

		//vFnImprimir("\ngetarg: nro %d, $%s$",iNumero,chrResultado);
		if (iK < (iAnchoMaximo - 1)) {
			return (1);
		} else {
			vFnImprimir("\ngetArg():El tamanio es invalido.");
			return (2);
		}
	} else {
		vFnImprimir("\ngetArg():parametro no encontrado.");
		return (0);
	}
}

/**
\fn void vFnImprimirContexto()
\brief Imprime la estetica de la ventana como los separadores y la informacion de atajos rapidos.
*/
void vFnImprimirContexto()
{
	vFnImprimirSeparadores();
	vFnImprimirMenu();
}

/**
\fn void vFnImprimirSeparadores()
\brief Imprime la estetica de la ventana.
*/
void vFnImprimirSeparadores()
{
	int iN;

	vFnImprimirVentana(HWND_SEP_CSW, "\n");
	vFnImprimirVentana(HWND_SEP_PROCESOS, "\n");
	vFnImprimirVentana(HWND_SEP_AYUDA, "\n");
	for (iN = 0; iN < 79; iN++) {
		vFnImprimirVentana(HWND_SEP_CSW, "%c", 0XC4);
		vFnImprimirVentana(HWND_SEP_PROCESOS, "%c", 0xCD);
		vFnImprimirVentana(HWND_SEP_AYUDA, "%c", 0xCD);
		vFnImprimirVentana(HWND_LOG_AYUDA, "%c", 0xCD);
	}
}

/**
\fn void vFnShell()
\brief Interpreta el buffer de cCaracteres y ejecuta los comandos ingresados.
\date 09/04/2006
*/
void vFnShell()
{
	

}				//Fin vFnShell()


/*****************************************************************************/
/*---------COMIENZO DE LA CODIFICACION DE LOS comandos DEL SHELL ------------*/
/*****************************************************************************/



/**
\fn void vFnImprimirMenu()
\brief Arma la barra inferior donde se comentan los comandos mÃ¡s importantes.
\date 09/04/2006
*/
void vFnImprimirMenu()
{
	if (uiModoMemoria == MODOPAGINADO) {
		vFnImprimirVentana(2,
				   "\n| ayuda | ps  |  init | mem |  pag  | cls  | F2: Log |");
	} else {
		vFnImprimirVentana(2,
				   "\n| ayuda | ps  |  init | mem | segs  | cls  | F2: Log |");
	}
	//WV: Imprime la ayuda en la ventana del log.
	vFnImprimirVentana(HWND_LOG_AYUDA,
			   "\n| ayuda LOG | ^:Arriba | v:Abajo | B:Borrar | F1: Shell |");
}

/**
\fn void vFnMenuAyuda()
\brief Muestra la ayuda en pantalla, para mÃ¡s ayuda escriba ayuda.
\date 09/04/2006
*/
void vFnMenuAyuda()
{
	
}
/**
\fn void vFnMenuVerSemaforos()
\brief Visualiza el estado de los Semaforos en el SODIUM.
\date 23/02/2008
*/
void vFnMenuVerSemaforos()
{
	int iN,iJ;


	vFnImprimir("\n\nSemaforos del Sistema:\n");
	for (iN=0;iN<CANTMAXSEM;iN++)
	{
		vFnImprimir("Valor: %d, Pshared: %d, Inicializado: %d, Cola: ",semaforosEnElSistema[iN].valor,semaforosEnElSistema[iN].pshared,semaforosEnElSistema[iN].inicializado);

		for (iJ=0;iJ<CANTMAXPROCCOLA;iJ++){
			vFnImprimir("[%d]",semaforosEnElSistema[iN].cola[iJ]);
		}

		vFnImprimir("\n");
	}
}

/**
\fn void vFnMenuVerShm()
\brief Visualiza el estado de la memoria compartida simulada por software.
\date 23/02/2008
*/
void vFnMenuVerShm()
{
	int iN,iJ;

	vFnImprimir("\n\nMemorias Compartidas del Sistema:\n");
	for (iN=0;iN<CANTMAXSHM;iN++)
	{
		vFnImprimir("Key: %d, Tamanio: %d, Declarada %d, Pids: ", memoriasCompartidas[iN].key, memoriasCompartidas[iN].tamanio, memoriasCompartidas[iN].declarada);

		for (iJ=0;iJ<CANTMAXPROCSHM;iJ++)
		{
			vFnImprimir("[%d]",memoriasCompartidas[iN].procAtt[iJ].pid);
		}

		vFnImprimir("\n");
	}
}

/**
\fn void vFnMenuInstanciarProceso()
\brief Instancia a un proceso (lado usuario) por linea de comando.
*/
void vFnMenuInstanciarProceso(char *stProceso, int iPrivilegio, int iArgumento)
{
    unsigned int uiPosicion;
    int iStatus;
    long lRetorno;

    uiPosicion = iFnInstanciarProceso(stProceso, iPrivilegio, iArgumento);

    ulPidProcesoForeground = pstuPCB[uiPosicion].ulId;
    //Esperamos a Init, asi no queda zombie, y ademas, lFnSysWaitPid se encarga
    //de eliminar el segmento del proceso hijo, por lo que no perdemos memoria
    lRetorno = lFnSysWaitPid( ulPidProcesoForeground, &iStatus, 0 );
}

/**
\fn void vFnMenuCambiaTeclado(int iComandoPos)
\brief Cambia la distribucion del teclado usada por el shell
\param iComandoPos PosiciÃ³n inicial del comando en el buffer de cCaracteres.
 Con esta informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la
 lÃ­nea de comandos.
\date 12/07/2008
*/
void vFnMenuCambiaTeclado(int iParam1)
{
    //char strArg1[10];
    //int iParam1;
    int estado=1;
	//TODO hacer que vuelva a tomar el codigo
    if (iParam1 > 0)
        estado=iFnCambiaTecladoI( iParam1 );
/*    else
        estado=iFnCambiaTecladoS( strArg1 );
	{
		vFnImprimir("\nError de parametro\n");
		return;
	}*/
    if (estado == 1)
    {
	vFnSysSetearColor(HWND_COMANDO, BLANCO_BRILLANTE);
	vFnImprimir("\nAyuda del comando cambiateclado:\n");
	vFnSysSetearColor(HWND_COMANDO, BLANCO);
	vFnImprimir("Forma de uso: Cmd>cambiateclado [NUMERO_DISTRIBUCION | CODIGO_DISTRIBUCION]\n"
	            "Las distribuciones existentes son:");
	vFnListarKeymaps();
    }
}

/**
\fn void vFnMenuCls()
\brief Limpia la pantalla, dejando al prompt en la Ãºltima lÃ­nea.
\date 09/04/2006
*/
void vFnMenuCls()
{
	vFnClsWin(HWND_COMANDO);
}

/**
\fn void vFnMenuVer()
\brief Limpia la pantalla y muestra el logo junto con la versiÃ³n del
 Sistema operativo
\date 02/05/2007
*/
void vFnMenuVer()
{
	vFnMenuCls();
	vFnImprimir("\nVersion: %s Pfff... recontra estable.",
		    VERSION_SODIUM);
}


/**
\fn void vFnMostrarListaParticiones()
\brief Muestra las particiones del heap de memoria alta del kernel
\date 14/11/2009
*/
void vFnMostrarListaParticiones()
 {
     long int liTamAnt;
     t_Nodo* ptrSig;
     int i;
     
     iModoFijo = iModoFijoUser;
     ptrHeap = ptrHeapAltoUsuario;
     liTamHeap = liTamanioHeapAltoUsuario;

     if(iModo == FIJO && iModoFijo == FIJO_EQUITATIVO)     liHeapEnd = (long int)ptrHeap + ((int)(liTamHeap)/liTamFija)*liTamFija;

     if(iModo == FIJO && iModoFijo == FIJO_PROPORCIONAL)    liHeapEnd =  liTamHeapFijoVariable;

     if(iModo == VARIABLE)   liHeapEnd = (long int)ptrHeap + liTamHeap;
     
     ptrActual = (t_Nodo*)ptrHeap;
     

     i = 1;

     vFnImprimir("\nListado de particiones en heap de memoria alta.");
     vFnImprimir("\n-----------------------------------------------");
     vFnImprimir("\nNumero de Particion             Tamanio (KB)              Libre/Usado");

     while((long int)ptrActual < liHeapEnd)
      {
       if((long int)ptrActual->liTam <= 0) break;
       vFnImprimir("\n             %d                  %d",i,(long int)ptrActual->liTam/1024);
       if(ptrActual->iUsado == LIBRE) vFnImprimir("                    Libre");
       else vFnImprimir("                    Usado");
       ptrActual = (t_Nodo*)((long int)ptrActual + (long int)ptrActual->liTam);
       i++;
      }


 }

/**
\fn void vFnMostrarTamaniosParticion()
\brief Muestra las porcentajes de particiones fijas del heap de memoria alta del kernel
\date 14/11/2009
*/
void vFnMostrarTamaniosParticion()
 {
    	int i;

	 i = 0;
	 vFnImprimir("\n\nLista de Tamanios de Particiones Fijas: ");
	 vFnImprimir("\n----------------------------------------- ");
	 vFnImprimir("\nNumero Particion                Porcentaje ");                  
	 while(piPorcentajesPartFija[i] != -1)
           {
		  vFnImprimir("\n      %d                              %d",i+1, piPorcentajesPartFija[i]);
		  i++;
	   } 

 }

/**
\fn void vFnBorrarUltimaPartFija()
\brief Borra la ultima particion fija agregada.
\date 14/11/2009
*/
void vFnBorrarUltimaPartFija()
 {
    	int i;
	i = 0;            
	while(piPorcentajesPartFija[i] != -1) i++;
	if(i > 1)piPorcentajesPartFija[i-1] = -1;
        else  vFnImprimir("\nNo puede dejar la lista de particiones vacia.2");  
 }

/**
\fn void vFnResetearListaPart()
\brief Resetea la lista de porcentajes de particiones fijas
\date 14/11/2009
*/
void vFnResetearListaPart()
 {            
	piPorcentajesPartFija[0] = -1;
        vFnImprimir("\nLista de porcentajes para particion fija proporcinal borrada\n Debe agregar alguna antes de inicializar un nuevo proceso.");
 }


/**
\fn void vFnAgregarPartFija()
\brief Agrega una particion fija.
\date 14/11/2009
*/
void vFnAgregarPartFija(char* stPorcentaje)
 {
    	int i;
        int iFlag;
        int iTotal;
        int iPorcentaje;
        iTotal = 0;
        iFlag = 0;
        iPorcentaje = iFnCtoi(stPorcentaje);

 	if(iPorcentaje <= 0 || iPorcentaje > 100) { vFnImprimir("\nValor invalido. Ingrese un porcentaje entre 1 y 100"); return;}
   	
        for (i = 0; i < 100; i++)
          {
            iTotal += piPorcentajesPartFija[i];
            if (iTotal + iPorcentaje > 100 && iFlag == 0) { piPorcentajesPartFija[i] = -1; vFnImprimir("\nMaximo excedido, eliminando hasta que entre..."); iFlag = 1;}
          }
        for (i = 99; i >= 0; i--) piPorcentajesPartFija[i] = piPorcentajesPartFija[i-1];
        piPorcentajesPartFija[0] = iPorcentaje;

 }



/**
\fn void vFnMenuMem()
\brief  Muestra por pantalla informaciÃ³n relevante a la memoria del Sistema
\date 01/05/2008
*/
void vFnMenuMem()
{
	unsigned int uiMemoriaUsada = MEM_BASE;	//partimos desde la memoria ya reservada para el so
	unsigned int uiMemoriaUsadaOverhead = MEM_BASE;
	unsigned int uiMemoriaDisponible = 0;
	unsigned int uiMemoriaPerdida;
	unsigned int uiMemoriaProceso;
        int uiMemoriaDisponibleProcesos;
	int iN = 0;

        uiMemoriaDisponibleProcesos =   uiTamanioMemoriaBios -= 1000000;
	
	// WV:En modo protegido no sedivide la memoria en convecional y alta.
	// vFnListarKMem();

	if (uiModoMemoria == MODOPAGINADO) {
        // PAGINACION
        // TODO Actualizar a las nuevas estrategias de asig. de memoria

		// Total de memoria usada y perdida.
		while (iN < CANTMAXPROCS) {
			if (pstuPCB[iN].iEstado != PROC_ELIMINADO
			    && pstuPCB[iN].iEstado !=
			    PROC_NO_DEFINIDO && pstuPCB[iN].ulId > 1) {
				uiMemoriaUsada += (pstuPCB[iN].uiTamProc);
				uiMemoriaUsadaOverhead +=
				    pstuPCB[iN].uiTamProc / 4096 * 4096;

				uiMemoriaUsadaOverhead += 4096 * (1 + pstuPCB[iN].uiTamProc / (iLimCantPaginasProceso * 4096));	//cada proceso tiene al menos 1 pag extra de PTABLE.

				if (pstuPCB[iN].uiTamProc % 4096 != 0)
					uiMemoriaUsadaOverhead += 4096;	//Se agrega para contabilizar la Fragmentacion Interna

			}
			iN++;
		}

		uiMemoriaDisponible = iTamanioMemoria * 8 * 4096 - uiMemoriaUsadaOverhead;
		uiMemoriaPerdida    = uiMemoriaUsadaOverhead - uiMemoriaUsada;

		// Memoria para el proceso mas grande.
		if (uiMemoriaDisponible - 4096 * (1 + uiMemoriaDisponible /
			    (iLimCantPaginasProceso * 4096)) >= 8192)
		{
			uiMemoriaProceso = uiMemoriaDisponible - 4096 * (1 + uiMemoriaDisponible /
							           (iLimCantPaginasProceso * 4096));
			} else {
			uiMemoriaProceso = 0;
		}

		//Ya tenemos floats, dividimos para pasar a Kb o Mb

		//En los dos primeros totales: De donde salia * 2^15 ?
		//Y si dividiamos despues por 2^20 directamente multiplicamos por 32

		//mem >> 20 => 2^20 = mem / 1.000.000.

		vFnImprimir("\nSimulando modelo de Memoria Paginada\n");
		vFnImprimir("------------------------------------\n" );
		vFnImprimir("  Memoria Total           = %.2f Mb (%db)\n",
			(float)iTamanioMemoria / 32, iTamanioMemoria<<15 );
		vFnImprimir("  Memoria utilizada       = %.2f Mb (%db)\n",
			(float)uiMemoriaUsada / (1024*1024), uiMemoriaUsada );
		vFnImprimir("  Memoria disponible      = %.2f Mb (%db)\n",
			(float)uiMemoriaDisponible / (1024*1024), uiMemoriaDisponible );
												vFnImprimir("  Memoria perdida por \n"
			    "   fragmentacion Interna  = %.2f Kb (%db)\n",
			    (float)uiMemoriaPerdida / 1024, uiMemoriaPerdida );
		vFnImprimir("  Capacidad maxima de un\n"
			    "   proceso en memoria     = %.2f Mb (%db)\n",
			    (float)uiMemoriaProceso / (1024*1024), uiMemoriaProceso );
	}
	else // SEGMENTACION
	{
        uiMemoriaUsada = 0;
        uiMemoriaPerdida = 0;
		// Total de memoria usada y perdida.
        for(iN =0; iN < CANTMAXPROCS; iN++) {
            if (pstuPCB[iN].iEstado != PROC_ELIMINADO &&
                pstuPCB[iN].iEstado != PROC_NO_DEFINIDO) {

                if(pstuPCB[iN].uiIndiceGDT_DS != 2) {
                    //No contamos los procesos kernel
                    uiMemoriaUsada += pstuPCB[iN].uiLimite;
                    uiMemoriaPerdida += pstuPCB[iN].uiTamanioOverhead;
                }
            }
        }

        //Asi se calcula en kernel/mem/memoria_k.h el total de memoria en el
        //heap de memoria alta del kernel
        iTamanioMemoria     = uiTamanioMemoriaBios - INICIO_MEMORIA_ALTA;

        //Ya tenemos floats, dividimos para pasar a Kb o Mb

        vFnImprimir("\nUtilizando Memoria Segmentada - Celdas de tamanio variable con granularidad 4K\n");
        vFnImprimir("-------------------------------------------------------------------------------\n" );
        vFnImprimir("  Resumen Heap memoria alta;\n");
        vFnImprimir("    Memoria Total                              = %.2f Mb "
                "(%db)\n",(float)iTamanioMemoria/(1024*1024), iTamanioMemoria );
        vFnImprimir("    Memoria utilizada                          = %.2f Mb "
                "(%db)\n", (uiMemoriaUsada)/
                (1024*1024),  uiMemoriaDisponibleProcesos);
        vFnImprimir("    Memoria utilizada por procesos usuario     = %.2f Mb "
                "(%db)\n",(float)uiMemoriaUsada / (1024*1024), uiMemoriaUsada );
        vFnImprimir("    Memoria disponible                         = %.2f Mb "
                "(%db)\n",(float)uiMemoriaDisponibleProcesos / (1024*1024),
                uiMemoriaDisponibleProcesos );
        vFnImprimir("    Memoria perdida por fragmentacion Interna  = %.2f Kb "
                "(%db)\n", (float)uiMemoriaPerdida / 1024, uiMemoriaPerdida );
    }

	vFnImprimir("-------------------------------------------\n" );

	vFnImprimir(" Memoria Total (BIOS)    = %.2f Mb (%db)\n",
	    (float)uiTamanioMemoriaBios / (1024*1024), uiTamanioMemoriaBios );
	vFnImprimir(" Tamanio del kernel      = %.2f Kb (%db)\n",
	    (float)uiTamanioKernel / 1024, uiTamanioKernel );
	vFnImprimir(" Tamanio del bss         = %.2f Kb (%db)\n",
	    (float)uiTamanioBSS /1024, uiTamanioBSS );
     //  while(1);
}


/**
\fn void vFnMenuPs()
\brief Muestra por pantalla los procesos activos
\date 09/04/2006
*/
void vFnMenuPs()
{
	int iN;
	for (iN = 0; iN < CANTMAXPROCS; iN++) {
		if (pstuPCB[iN].iEstado != PROC_ELIMINADO
		    && pstuPCB[iN].iEstado != PROC_NO_DEFINIDO) {
			vFnImprimir
			    ("\nPid=%d, PPid=%d, %s, IndiceGDT=%d, Tam=%d bytes, Estado= ",
			     pstuPCB[iN].ulId,
			     pstuPCB[iN].ulParentId,
			     pstuPCB[iN].stNombre,
			     pstuPCB[iN].uiIndiceGDT_TSS,
			     pstuPCB[iN].uiTamProc);

			switch (pstuPCB[iN].iEstado) {
			case PROC_EJECUTANDO:
				vFnImprimir("Ejecutando ");
				break;
			case PROC_LISTO:
				vFnImprimir("Listo      ");
				break;
			case PROC_ESPERANDO:
				vFnImprimir("Esperando  ");
				break;
			case PROC_DETENIDO:
				vFnImprimir("Detenido   ");
				break;
			case PROC_ELIMINADO:
				vFnImprimir("Eliminado  ");
				break;
			case PROC_ZOMBIE:
				vFnImprimir("Zombie     ");
				break;
			default:
				vFnImprimir("%d", pstuPCB[iN].iEstado);
				break;
			}
		}
	}
}


/**
\fn void vFnMenuDesc(int iArgumento)
\brief Devuelve el contenido de los descriptores para el Pid pasado por parÃ metro
 Si no lo encuentra, imprime las 20 primeras posiciones de la GDT
\param iComandoPos Pid pasado por parÃ metro.
\date: 18/04/2008	//modificado: 22/08/09
\autor: Gerardo Puyo
*/
void vFnMenuDesc(int iArgumento,int iArgumento2)
{
	char stArg1[16],* stPos;
	int iArg1 = 0,iPosProc,iValor,iPos1,iPos2,iN;
//	dword *pdwVolcado; //No se esta utilizando

	iFnCopiaCadena((char*)iArgumento, stArg1);

	if (stArg1[0] != '\0') {	//Si recibio algo...
		iArg1 = iFnCtoi(stArg1);
		if (iFnEsNumero(stArg1)==0)
		{
			iPosProc=iFnBuscaPosicionProc(iArg1);
			if (iPosProc!=-1)
			{
				if(iArgumento2==1)
				{  	
				vFnImprimir("\n Proceso %d, indice en la PCB %d, indice en la GDT %d",iArg1, iPosProc,pstuPCB[iPosProc].uiIndiceGDT_CS);
			  	vFnImprimir("\n Descriptor de CÃ²digo");
			  	vFnImprimir("\n Limite bajo: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_CS].usLimiteBajo);
			  	vFnImprimir("\n Limite Alto: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_CS].bitLimiteAlto);
		  	  	vFnImprimir("\n Base Bajo: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_CS].usBaseBajo);
			  	vFnImprimir("\n Base Medio: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_CS].ucBaseMedio);
			  	vFnImprimir("\n Base Alto: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_CS].usBaseAlto);
			  	vFnImprimir("\n Acceso: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_CS].ucAcesso);
			  	vFnImprimir("\n Granularidad: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_CS].bitGranularidad);
				}
				if(iArgumento2==2)
				{
				vFnImprimir("\n Proceso %d, indice en la PCB %d, indice en la GDT %d",iArg1, iPosProc,pstuPCB[iPosProc].uiIndiceGDT_DS);
			  	vFnImprimir("\n Descriptor de Datos");
			  	vFnImprimir("\n Limite bajo: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_DS].usLimiteBajo);
			  	vFnImprimir("\n Limite Alto: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_DS].bitLimiteAlto);
		  	  	vFnImprimir("\n Base Bajo: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_DS].usBaseBajo);
			  	vFnImprimir("\n Base Medio: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_DS].ucBaseMedio);
			  	vFnImprimir("\n Base Alto: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_DS].usBaseAlto);
			  	vFnImprimir("\n Acceso: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_DS].ucAcesso);
			  	vFnImprimir("\n Granularidad: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_DS].bitGranularidad);
				}
				if(iArgumento2==3)
				{
				vFnImprimir("\n Proceso %d, indice en la PCB %d, indice en la GDT %d",iArg1, iPosProc,pstuPCB[iPosProc].uiIndiceGDT_TSS);
			  	vFnImprimir("\n Descriptor de TSS");
			  	vFnImprimir("\n Limite bajo: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_TSS].usLimiteBajo);
			  	vFnImprimir("\n Limite Alto: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_TSS].bitLimiteAlto);
		  	  	vFnImprimir("\n Base Bajo: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_TSS].usBaseBajo);
			  	vFnImprimir("\n Base Medio: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_TSS].ucBaseMedio);
			  	vFnImprimir("\n Base Alto: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_TSS].usBaseAlto);
			  	vFnImprimir("\n Acceso: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_TSS].ucAcesso);
			  	vFnImprimir("\n Granularidad: %x ",pstuTablaGdt->stuGdtDescriptorDescs[pstuPCB[iPosProc].uiIndiceGDT_TSS].bitGranularidad);
				}	
		 	}
			else
			vFnMenuGdt(-1);
		}
		else
		{
		iValor=iFnBuscarEnCadena(stArg1,"-",0);
		if(iValor<0)
			{
			 vFnMenuGdt(-1);
			}
		else
			{
			stPos=pstFnCadenaIzquierda(stArg1,iValor-1);
			if (iFnEsNumero(stPos)==0)
			 {
				iPos1=iFnCtoi(stPos);
				stPos=pstFnCadenaDerecha(stArg1,iFnLongitudCadena(stArg1)-iValor-1);
				if (iFnEsNumero(stPos)<0)
					vFnMenuGdt(-1);
				iPos2=iFnCtoi(stPos);
				if(iPos1<8192 && iPos1>=0 && iPos2>0 && iPos2<=8192)
					{
					  for(iN=iPos1;iN<iPos2;iN++)
					  {
						vFnImprimir("\n Limite bajo: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iN].usLimiteBajo);
						vFnImprimir("\n Limite Alto: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iN].bitLimiteAlto);
	  					vFnImprimir("\n Base Bajo: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iN].usBaseBajo);
						vFnImprimir("\n Base Medio: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iN].ucBaseMedio);
						vFnImprimir("\n Base Alto: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iN].usBaseAlto);
						vFnImprimir("\n Acceso: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iN].ucAcesso);
						vFnImprimir("\n Granularidad: %x \n",pstuTablaGdt->stuGdtDescriptorDescs[iN].bitGranularidad);
						//SHELL_INTERACTIVO;
					  }
					}
				else
					vFnMenuGdt(-1);
			 }
			else
				vFnMenuGdt(-1);
			}
		}
	} else {
		/*vFnImprimir
		    ("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>desc [indice]");*/
		vFnMenuGdt(-1);
	}
}





//Inicio modificacion Fernando***********
//***************************************

/**
\fn void vFnMenuDump(iComandoPos)
\brief Vuelca en pantalla el contenido de las direcciones de memoria.
Desde lÃ­nea de comandos se ingresan como parÃ¡metros la posiciÃ³n inicial
desde donde queremos leer, ya sea en hexa como en decimal, y la cantidad
de doublewords que queremos leer. Util para debuguear lo indebugeable.
\param iComandoPos PosiciÃ³n inicial del comando en el buffer de cCaracteres.
 Con esta informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la
 lÃ­nea de comandos.
\date 09/04/2006
*/
//Funcion utilizada en shell modo kernel
/*void vFnMenuDump(iComandoPos)
{
	int iArg2 = 0;
	int iN;
	char stArg1[16];
	char stArg2[16];
	dword *pdwVolcado;
	if ((iFnGetArg(iComandoPos, 1, stArg1, 16) == 1)
	    && (iFnGetArg(iComandoPos, 2, stArg2, 16) == 1)) {
		pdwVolcado = (unsigned int *) iFnXtoi(stArg1);
		iArg2 = iFnXtoi(stArg2);
		vFnImprimir
		    ("\nIniciando vuelco de memoria de %d dwords, desde %d",
		     iArg2, pdwVolcado);
		cFnPausa();

		for (iN = 0; iN < iArg2; iN++) {
			vFnImprimir("\ni= %d Dir: %x, cont: %x",
				    iN, &pdwVolcado[iN],
				    (unsigned int) pdwVolcado[iN]);
			if (((iN +
			      1) %
			     (pstuVentana[HWND_COMANDO].iAlto -
			      1)) == 0 && iN > 0)
			{
				SHELL_INTERACTIVO;
			}
		}
		vFnImprimir("\nFin");
	} else {
		vFnImprimir
		    ("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>dump [dir mem] [intervalo]");
	}
}*/


//NIKO
/**
 * @brief Lee el primer sector
 * @param iComandoPos Con la posiciÃ³n donde terminÃ³ la cadena para poder obtener los parÃ¡metros
 * @date 04/08/2008
 */
/*
void vFnMenuLeerArch(int iComandoPos)
{
	char stArg1[14];

	if (iFnGetArg(iComandoPos, 1, stArg1, 14) == 1) {
		__asm__ volatile("sti");
		vFnDispLeerArchivo(stArg1);
		__asm__ volatile("cli");
	} else {
		vFnImprimir("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>leer [nombre_archivo]");
		return;
	}
}
*/

/**
\fn void vFnMenuKillSeg(int iComandoPos)
\brief Comando utilizado matar procesos del sistema.
\param iComandoPos PosiciÃ³n inicial del comando en el buffer de cCaracteres.
 Con esta informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la
 lÃ­nea de comandos.
*/
/*
void vFnMenuKillSeg(int iComandoPos)
{
	char stArg1[16];
	int iProcPos, iPid;
	if ((iFnGetArg(iComandoPos, 1, stArg1, 16) == 1)) {
		iPid = iFnCtoi(stArg1);
		if ((iProcPos = iFnBuscaPosicionProc(iPid)) != -1) {
			if ((iPid != 0) && (iPid != 1)
			    && (pstuPCB[iProcPos].iEstado !=
				PROC_ELIMINADO)) {
                    //Liberamos el segmento que usa el proceso
                    /* En realidad, lo unico que se esta eliminando aqui es el
                     * bloque de memoria que se creo con el comando exec, ya
                     * que los procesos creados con iFnNuevaTareaEspecial usan
                     * como Stack parte de su TSS (espacio0, espacio1, etc).
                     */
                   /* vFnKFree( (void*)pstuPCB[iProcPos].uiDirBase );
					pstuPCB[iProcPos].iEstado =
					    PROC_ELIMINADO;
					vFnImprimir
					    ("\n OK, PID=%d, POS=%d, ESTADO=%d",
					     pstuPCB[iProcPos].
					     ulId, iProcPos,
					     pstuPCB[iProcPos].iEstado);
//				}
			} else {
				vFnImprimir
				    ("\nno se puede matar al proceso %d",
				     iPid);
			}
		} else {
			vFnImprimir
			    ("\nEl pid ingresado no corresponde a un abonado en servicio...");
		}
	} else {
		vFnImprimir
		    ("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>kill [pid]");
	}
}*/

/**
\fn void vFnMenuKill(int iComandoPos)
\brief ImplementaciÃ³n del comando kill. Elimina al proceso solicitado por lÃ­nea de comandos.
\param iComandoPos PosiciÃ³n inicial del comando en el buffer de cCaracteres. Con esta
 informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la lÃ­nea de comandos.
\date 09/04/2006
*/
/*
void vFnMenuKill(int iComandoPos)
{
	char stArg1[16];
	int iProcPos, iPid;
	if ((iFnGetArg(iComandoPos, 1, stArg1, 16) == 1)) {
		iPid = iFnCtoi(stArg1);

		if ((iProcPos = iFnBuscaPosicionProc(iPid)) != -1) {
			if ((iPid != 0) && (iPid != 1)
			    && (pstuPCB[iProcPos].iEstado !=
				PROC_ELIMINADO)) {
				pstuPCB[iProcPos].iEstado = PROC_ELIMINADO;
                    iFnLimpiarMemoria( pstuPCB[iProcPos].uiTamProc,
                                       pstuPCB[iProcPos].pstuTablaPaginacion);
				vFnImprimir
				    ("\n OK, PID=%d, POS=%d, ESTADO=%d",
				     pstuPCB[iProcPos].ulId,
				     iProcPos, pstuPCB[iProcPos].iEstado);
			} else {
				vFnImprimir
				    ("\n No se puede matar al proceso %d",
				     iPid);
			}
		} else {
			vFnImprimir
			    ("\nEl pid ingresado no corresponde a un abonado en servicio...");
		}
	} else {
		vFnImprimir
		    ("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>kill [pid]");
	}
}
*/

/**
 * @brief Ejecuta el comando CD
 * @param iComandoPos Con la posiciÃ³n donde terminÃ³ la cadena para poder obtener los parÃ¡metros
 * @date 04/08/2008
 *//*
void vFnMenuCD(int iComandoPos)
{
	iFnCopiaCadena(stuPATHCD[0].PATH ,' ');
	char ruta[255];
	char AUX_PATH[255];
	int cluster= 0 , i;


	if(iFnGetArg(iComandoPos, 1, ruta, 255) == 1)
	{
		if(iFnCompararCadenas(ruta, "/") !=1)//pregunto si es / (raiz), ya q siempre va a existir no es necesario verificar.
		{
			//Si ruta no tiene / la copio a AUX_PATH
			//iFnCopiaCadena(AUX_PATH ,PATH);
			if (ruta[0] =='/' )
			{
				vFnImprimir("Argumento invalido\n");
				return;
			}
			else
			{
				iFnCopiaCadena(AUX_PATH  ,ruta);

			}
			cluster= iFnBuscarDirectorio(AUX_PATH,pstuFsFatHandleHandle);
			if (cluster==0)
			{
				vFnImprimir("Ruta no valida\n");
				vFnInicializarPath();
				return;
			}
			iFnCopiaCadena(stuPATHCD[0].PATH ,ruta);
			stuPATHCD[0].cluster =cluster ;
			return;

		}//viene por aca si es un CD al raiz
		iFnCopiaCadena(stuPATHCD[0].PATH ,ruta);//Copio '/' a la estructura que contiene el path actual
		stuPATHCD[0].cluster =cluster ;
	}
	else
	{
		stuPATHCD[0].PATH[0]='-';
		vFnImprimir("Argumento invalido\n");
	}


}*/



/**
 * @brief Ejecuta el comando RM
 * @param iComandoPos Con la posiciÃ³n donde terminÃ³ la cadena para poder obtener los parÃ¡metros
 * @date 04/08/2008
 */
/*
void vFnMenuRm(int iComandoPos)
{

	char ruta[255];

	if(iFnGetArg(iComandoPos, 1, ruta, 255) == 1)
	{
 		vFnBorrarArcFat(pstuFsFatHandleHandle, ruta);

	}
}*/

/**
 * @brief Escribe en el archivo
 * @param iComandoPos Con la posiciÃ³n donde terminÃ³ la cadena para poder obtener los parÃ¡metros
 * @date 04/08/2008
 */
/*void vFnMenuWriteArch(int iComandoPos)
{
	char stArg1[14];
	char stArg2[128];
	dword cluster;
	if ((iFnGetArg(iComandoPos, 1, stArg1, 14) == 1) && (iFnGetArg2(iComandoPos, 2, stArg2, 128) == 1))
	{
		__asm__ volatile("sti");
		iFnDispEscribirArchivo(stArg1, stArg2);
		__asm__ volatile("cli");
	}
	else
	{
		vFnSysSetearColor(HWND_COMANDO,BLANCO_BRILLANTE);
		vFnImprimir ("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>write [archivo] [contenido]");
		vFnSysSetearColor(HWND_COMANDO, BLANCO);
	}
}*/




//****************************************************************************
//Shell usuario***************************************************************
//****************************************************************************


/**
\fn void vFnMenuDump(iPid)
\brief Vuelca en pantalla el contenido de las direcciones de memoria.
Desde lÃ­nea de comandos se ingresan como parÃ¡metros la posiciÃ³n inicial
desde donde queremos leer, ya sea en hexa como en decimal, y la cantidad
de doublewords que queremos leer. Util para debuguear lo indebugeable.
\param iPid
 Con esta informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la
 lÃ­nea de comandos.
\date 09/04/2006
*/
void vFnMenuDump(int iArg1, int iArg2)
{
	dword *pdwVolcado;
	pdwVolcado = (unsigned int *) iArg1;
	vFnImprimir("\ni= %d Dir: %x, cont: %x",iArg2, &pdwVolcado[iArg2],(unsigned int) pdwVolcado[iArg2]);
}

//NIKO
/**
 * @brief Lee el primer sector
 * @param iPid
 * @date 04/08/2008
 */
void vFnMenuLeerArch(int iArg1)
{
  char stArg1[32];


	
  iFnCopiaCadena(stArg1, (char*)iArg1);

  
	if (stArg1[0] != '\0') {
	    __asm__ ("sti"::);
		vFnDispLeerArchivo(stArg1);
		 __asm__ ("cli"::);
		
	} 
  else {
		vFnImprimir("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>leer [nombre_archivo]");
	}
	

	return;
}


/**
\fn void vFnMenuOptKillm()
\Ejecuta un kill de acuerdo al modo de direccionamiento utilizado.
\date 17/08/2009
*/
void vFnMenuOptKill(int iPid)
{
	if (uiModoMemoria == MODOPAGINADO)
		vFnMenuKill(iPid);
	else//segmentacion
		vFnMenuKillSeg(iPid);
}

/**
\fn void vFnMenuKillSeg(int iPid)
\brief Comando utilizado matar procesos del sistema.
\param iPid
 Con esta informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la
 lÃ­nea de comandos.
*/
void vFnMenuKillSeg(int iPid)
{
	int iProcPos;
	if (iPid > 0) {
		if ((iProcPos = iFnBuscaPosicionProc(iPid)) != -1) {
			if ((iPid != 0) && (iPid != 1)
			    && (pstuPCB[iProcPos].iEstado !=
				PROC_ELIMINADO)) {
                    //Liberamos el segmento que usa el proceso
                    /* En realidad, lo unico que se esta eliminando aqui es el
                     * bloque de memoria que se creo con el comando exec, ya
                     * que los procesos creados con iFnNuevaTareaEspecial usan
                     * como Stack parte de su TSS (espacio0, espacio1, etc).
                     */
                    vFnKFree( (void*)pstuPCB[iProcPos].uiDirBase );
					pstuPCB[iProcPos].iEstado =
					    PROC_ELIMINADO;
					vFnImprimir
					    ("\n OK, PID=%d, POS=%d, ESTADO=%d",
					     pstuPCB[iProcPos].
					     ulId, iProcPos,
					     pstuPCB[iProcPos].iEstado);
//				}
			} else {
				vFnImprimir
				    ("\nno se puede matar al proceso %d",
				     iPid);
			}
		} else {
			vFnImprimir
			    ("\nEl pid ingresado no corresponde a un abonado en servicio...");
		}
	} else {
		vFnImprimir
		    ("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>kill [pid]");
	}
}

/**
\fn void vFnMenuKill(int iPid)
\brief ImplementaciÃ³n del comando kill. Elimina al proceso solicitado por lÃ­nea de comandos.
\param iPid
 informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la lÃ­nea de comandos.
\date 09/04/2006
*/
void vFnMenuKill(int iPid)
{
	int iProcPos;
	if (iPid > 0) {
		if ((iProcPos = iFnBuscaPosicionProc(iPid)) != -1) {
			if ((iPid != 0) && (iPid != 1)
			    && (pstuPCB[iProcPos].iEstado !=
				PROC_ELIMINADO)) {
				pstuPCB[iProcPos].iEstado = PROC_ELIMINADO;
                    iFnLimpiarMemoria( pstuPCB[iProcPos].uiTamProc,
                                       pstuPCB[iProcPos].pstuTablaPaginacion);
				vFnImprimir
				    ("\n OK, PID=%d, POS=%d, ESTADO=%d",
				     pstuPCB[iProcPos].ulId,
				     iProcPos, pstuPCB[iProcPos].iEstado);
			} else {
				vFnImprimir
				    ("\n No se puede matar al proceso %d",
				     iPid);
			}
		} else {
			vFnImprimir
			    ("\nEl pid ingresado no corresponde a un abonado en servicio...");
		}
	} else {
		vFnImprimir
		    ("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>kill [pid]");
	}
}


/**
 * @brief Ejecuta el comando CD
 * @param iArg1
 * @date 04/08/2008
 */
void vFnMenuCD(int iArg1)
{
	iFnCopiaCadena(stuPATHCD[0].stPATH ,' ');
	char stRuta[255];
	char AUX_PATH[255];
	int iCluster= 0 , i;

	iFnCopiaCadena(stRuta, (char*)iArg1);

	if(stRuta[0] != '\0')
	{
		if(iFnCompararCadenas(stRuta, "/") !=1)//pregunto si es / (raiz), ya q siempre va a existir no es necesario verificar.
		{
			//Si stRuta no tiene / la copio a AUX_PATH
			//iFnCopiaCadena(AUX_PATH ,PATH);
			if (stRuta[0] =='/' )
			{
				vFnImprimir("Argumento invalido\n");
				return;
			}
			else
			{
				iFnCopiaCadena(AUX_PATH  ,stRuta);

			}
			iCluster= iFnBuscarDirectorio(AUX_PATH,pstuFsFatHandleHandle);
			if (iCluster==0)
			{
				vFnImprimir("Ruta no valida\n");
				vFnInicializarPath();
				return;
			}
			iFnCopiaCadena(stuPATHCD[0].stPATH ,stRuta);
			stuPATHCD[0].iCluster =iCluster ;
			return;

		}//viene por aca si es un CD al raiz
		iFnCopiaCadena(stuPATHCD[0].stPATH ,stRuta);//Copio '/' a la estructura que contiene el path actual
		stuPATHCD[0].iCluster =iCluster ;
	}
	else
	{
		stuPATHCD[0].stPATH[0]='-';
		vFnImprimir("Argumento invalido\n");
	}


}


/**
 * @brief Ejecuta el comando LS
 * @param iArg1
 * @date 04/08/2008
 */
void vFnMenuLs(int iArg1)
{
	char stRuta[255];
	int iCluster;
	iCluster = 0;

	__asm__ ("sti"::);
	iFnCopiaCadena(stRuta, (char*)iArg1);
	vFnListarContenidoSubDir(stRuta);
	__asm__ ("cli"::);
	
}


/**
 * @brief Ejecuta el comando RM
 * @param iArg1
 * @date 04/08/2008
 */
void vFnMenuRm(int iArg1)
{

	char stRuta[255];

	iFnCopiaCadena(stRuta, (char*)iArg1);

	if(stRuta[0] != '\0')
	{
 		vFnBorrarArcFat(pstuFsFatHandleHandle, stRuta);//delete( stRuta);

	}
}

/**
 * @brief Escribe en el archivo
 * @param iComandoPos Con la posiciÃ³n donde terminÃ³ la cadena para poder obtener los parÃ¡metros
 * @date 04/08/2008
 */
void vFnMenuWriteArch(int iArg1, int iArg2)
{
	char stArg1[14];
	char stArg2[128];
	dword iCluster;



	iFnCopiaCadena(stArg1, (char*)iArg1);
	iFnCopiaCadena(stArg2, (char*)iArg2);

	if (stArg1[0] != '\0' && stArg2[0] != '\0')
	{
		__asm__ volatile ("sti");
		iFnDispEscribirArchivo(stArg1, stArg2);
			__asm__ volatile ("cli");
	}
	else
	{
		vFnSysSetearColor(HWND_COMANDO,BLANCO_BRILLANTE);
		vFnImprimir ("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>write [archivo] [contenido]");
		vFnSysSetearColor(HWND_COMANDO, BLANCO);
	}
	


}

//Fin modificacion Fernando**************
//***************************************







/**
\fn void vFnMenuStack(iPid, iRing)
\brief Vuelca en pantalla el contenido del stack del proceso deseado.
Util para debuguear lo indebugeable.
\param iPid PID del proceso del que se quiere ver el stack.
Por el momento el parametro RING no tiene uso.
\date 09/04/2006
\modificado 08/08/2009
*/
void vFnMenuStack(int iPid,int iRing)
{
	int iTSS, iPCB;
	int iN, iEstadoAnterior, iCantidadDWordsStack;
	dword *pdwVolcado;

	iPCB = iFnBuscaPosicionProc(iPid);
	if (iPCB > 0 && pstuPCB[iPCB].iEstado != PROC_ELIMINADO)
	{
		iTSS = pstuPCB[iPCB].ulLugarTSS;
		iEstadoAnterior = pstuPCB[iPCB].iEstado;
		vFnImprimir ("\nIntentando congelar al Proceso %d", iPid);
		if (iEstadoAnterior != PROC_EJECUTANDO)
		{
			pstuPCB[iPCB].iEstado = PROC_DETENIDO;
			vFnImprimirOk(55);
			vFnImprimir("\nesp: %x",stuTSSTablaTareas[iTSS].esp);
			vFnImprimir("\nebp: %x",stuTSSTablaTareas[iTSS].ebp);

			vFnImprimir("\nIniciando vuelco de stack: TOS=esp=0x%x, Segmento de stack=ss=0x%x, Dir. base=0x%x",stuTSSTablaTareas[iTSS].esp,stuTSSTablaTareas[iTSS].ss,pstuPCB[iPCB].uiDirBase);

			if (pstuPCB[iPCB].uiDirBase)
			{
				vFnImprimir("\nProceso de usuario (Dir. base != 0x0)");

				switch (iRing)
				{
					case 3:
						pdwVolcado = (unsigned int *) pstuPCB[iPCB].uiDirBase +stuTSSTablaTareas[iTSS].esp;
                        //TODO - Revisar cambio:
                        //pstuPCB.uiLimite no corresponde a la direccion
                        //absoluta de limite, sino a la LONGITUD del segmento
						//iCantidadDWordsStack = pstuPCB[iPCB].uiLimite -
                        //    stuTSSTablaTareas[iTSS].esp;
						iCantidadDWordsStack = (pstuPCB[iPCB].uiLimite +pstuPCB[iPCB].uiDirBase  ) -stuTSSTablaTareas[iTSS].esp;
						vFnImprimir("\nValores calculados: Dir. inicial volcado=0x%x, Cant.Words=%d",pdwVolcado,iCantidadDWordsStack);
						break;
					default:
						vFnImprimir("\nSeleccion no valida: RING=%d",iRing);
						return;
				}

			}
			else
			{
				switch (iRing)
				{
					case 0:
						pdwVolcado = (unsigned int *)stuTSSTablaTareas[iTSS].espacio0;
						iCantidadDWordsStack =TSS_TAMANIO_STACK_R0 / 4;
						break;
					case 1:
						pdwVolcado = (unsigned int *)stuTSSTablaTareas[iTSS].espacio1;
						iCantidadDWordsStack =TSS_TAMANIO_STACK_R1 / 4;
						break;
					case 2:
						pdwVolcado = (unsigned int *)stuTSSTablaTareas[iTSS].espacio2;
						iCantidadDWordsStack =TSS_TAMANIO_STACK_R2 / 4;
						break;
					default:
						pdwVolcado = (unsigned int *)stuTSSTablaTareas[iTSS].espacio0;
						iCantidadDWordsStack =TSS_TAMANIO_STACK_R0 / 4;
				}
			}
			vFnImprimir("\niCantidadDWordsStack: %d\n",iCantidadDWordsStack);
			for (iN = 0;iN < iCantidadDWordsStack; iN++)
			{
				vFnImprimir("\nP: %d  Dir: 0x%x\tCont: %x%x%x%x%x%x%x%x \t %c%c%c%c",iN, &pdwVolcado[iN],(unsigned int) (pdwVolcado[iN]>> 28) & 0xF,(unsigned int) (pdwVolcado[iN]>> 24) & 0xF,(unsigned int) (pdwVolcado[iN]>> 20) & 0xF,(unsigned int) (pdwVolcado[iN]>> 16) & 0xF,(unsigned int) (pdwVolcado[iN]>> 12) & 0xF,(unsigned int) (pdwVolcado[iN]>> 8) & 0xF,(unsigned int) (pdwVolcado[iN]>> 4) & 0xF,(unsigned int) (pdwVolcado[iN])& 0xF,(unsigned char) (pdwVolcado[iN]>> 24) & 0xFF,(unsigned char) (pdwVolcado[iN]>> 16) & 0xFF,(unsigned char) (pdwVolcado[iN]>> 8) & 0xFF,(unsigned char) (pdwVolcado[iN]) & 0xFF);

				if (&pdwVolcado[iN] ==(unsigned int *)stuTSSTablaTareas[iTSS].esp)vFnImprimir(" <-esp (TOP OF STACK)");

				if (&pdwVolcado[iN] ==(unsigned int *)stuTSSTablaTareas[iTSS].ebp)vFnImprimir(" <-ebp (STACK FRAME POINTER)");

				if (((iN +1) %(pstuVentana[HWND_COMANDO].iAlto - 1)) == 0 && iN > 0)
				{
				}
			}

			vFnImprimir("\nReanudando Proceso %d", iPid);
			pstuPCB[iPCB].iEstado = iEstadoAnterior;
			vFnImprimirOk(55);

			vFnImprimir("\nFin");

		}
		else
		{
			vFnImprimirNOk(55);
			vFnImprimir("\nJejeje... Hablando del principio de incertidumbre...");

		}
	}
	else
	{
		vFnImprimir("\nEl pid indicado no pertenece a un abonado en servicio...");
		vFnImprimir("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>stack [pid] [ring]");
	}

	return;
}

/**
\fn void vFnMenuGdt(int iComandoPos)
\brief Muestra por pantalla las primeras 20 posiciones de la GDT, en caso de que
no se ingresen parÃ¡metros. De lo contrario muestra la posiciÃ³n pasada.
\param iComandoPos PosiciÃ³n inicial del comando en el buffer de cCaracteres.
Con esta informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la
 lÃ­nea de comandos.
\date 21/07/2008
*/
void vFnMenuGdt(int iParam) //..GDT
{
	char stArg[25];
	int iSinParam = 0;
	int iPos;


	dword *pdwVolcado;

	vFnImprimir("\nPosicion inicial de la gdt: %x ", pstuTablaGdt);
	vFnImprimir("\nComienzo del volcado de memoria:");
	pdwVolcado = (dword *) pdwGDT;


			vFnImprimir("\n Limite bajo: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iParam].usLimiteBajo);
			vFnImprimir("\n Limite Alto: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iParam].bitLimiteAlto);
		  	vFnImprimir("\n Base Bajo: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iParam].usBaseBajo);
			vFnImprimir("\n Base Medio: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iParam].ucBaseMedio);
			vFnImprimir("\n Base Alto: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iParam].usBaseAlto);
			vFnImprimir("\n Acceso: %x ",pstuTablaGdt->stuGdtDescriptorDescs[iParam].ucAcesso);
			vFnImprimir("\n Granularidad: %x \n",pstuTablaGdt->stuGdtDescriptorDescs[iParam].bitGranularidad);
   return 0;
}


/**
\fn void vFnMenuIdt(int iParam)
\brief Muestra por pantalla el contenido de una posicion de la IDT pasado por parametro.
\param iParam posicion de la IDT a mostrar.
\date 09/04/2006
\modificado 09/08/2009
*/
void vFnMenuIdt(int iParam)
{
	
	dword *pdwVolcado;

	vFnImprimir("\nPosicion inicial de la idt: %x ", pstuIDT);
	vFnImprimir("\nComienzo del volcado de memoria:");
	
	pdwVolcado = (dword *) pstuIDT;

	vFnImprimir("\ni= %d Dir: %x, cont: %x", iParam, pdwVolcado+iParam, (unsigned int) *(pdwVolcado+iParam));
	
	return 0;

}

/**
\fn void vFnMenuTSS(int iPid)
\brief Muestra por pantalla la TSS del proceso especificado por lÃ­nea
 de comandos.
\param iPid PID del proceso cuya TSS se muestra
\date 09/04/2008
\modificado 08/08/2009
*/
void vFnMenuTSS(int iPid)
{
	int iPCB, iTSS, iEstadoAnterior=-1;

	iPCB = iFnBuscaPosicionProc(iPid);

	if (iPCB < 0) {
		vFnImprimir ("\nEl pid indicado no pertenece a un abonado en servicio...\nForma de uso: Cmd>tss [pid]\n");
		return;
	}

	iEstadoAnterior = pstuPCB[iPCB].iEstado;
	vFnImprimir ("\nIntentando detener al Proceso %d", iPid);
	if (iEstadoAnterior != PROC_EJECUTANDO) {
		pstuPCB[iPCB].iEstado = PROC_DETENIDO;
		vFnImprimirOk(55);

	} else {
		vFnImprimirNOk(55);
		vFnImprimir ("\nJejeje... Hablando del principio de incertidumbre...");
		return;
	}

	vFnImprimir (	"\nMostrando contenido de la TSS:");

	iTSS = pstuPCB[iPCB].ulLugarTSS;


	vFnImprimir(	"\n IndiceTSS = %d, direccion lineal: %x",	\
			iTSS,				\
			(unsigned int)&stuTSSTablaTareas[iTSS]);
  	vFnImprimir(	"\n esp0:\t%d\t(0x%x)\tss0:\t%d\t(0x%x)",	\
			stuTSSTablaTareas[iTSS].esp0,	\
			stuTSSTablaTareas[iTSS].esp0,	\
			stuTSSTablaTareas[iTSS].ss0,	\
			stuTSSTablaTareas[iTSS].ss0);
  	vFnImprimir(	"\n esp1:\t%d\t(0x%x)\tss1:\t%d\t(0x%x)",	\
			stuTSSTablaTareas[iTSS].esp1,	\
			stuTSSTablaTareas[iTSS].esp1,	\
			stuTSSTablaTareas[iTSS].ss1,	\
			stuTSSTablaTareas[iTSS].ss1);
	vFnImprimir(	"\n esp2:\t%d\t(0x%x)\tss2:\t%d\t(0x%x)",	\
			stuTSSTablaTareas[iTSS].esp2,	\
			stuTSSTablaTareas[iTSS].esp2,	\
			stuTSSTablaTareas[iTSS].ss2,	\
			stuTSSTablaTareas[iTSS].ss2);
	vFnImprimir(	"\n cr3:\t%d\t(0x%x)",				\
			stuTSSTablaTareas[iTSS].cr3,	\
			stuTSSTablaTareas[iTSS].cr3);
	vFnImprimir(	"\n eip:\t%d\t(0x%x)",				\
			stuTSSTablaTareas[iTSS].eip,	\
			stuTSSTablaTareas[iTSS].eip);
	vFnImprimir(	"\n uiEFlags:\t%d\t(0x%x)",			\
			stuTSSTablaTareas[iTSS].uiEBandera,	\
			stuTSSTablaTareas[iTSS].uiEBandera);
	vFnImprimir(	"\n eax:\t%d\t(0x%x)\tecx:\t%d\t(0x%x)",		\
			stuTSSTablaTareas[iTSS].eax,	\
			stuTSSTablaTareas[iTSS].eax,	\
			stuTSSTablaTareas[iTSS].ecx,	\
			stuTSSTablaTareas[iTSS].ecx);
	vFnImprimir(	"\n edx:\t%d\t(0x%x)\tebx:\t%d\t(0x%x)",		\
			stuTSSTablaTareas[iTSS].edx,	\
			stuTSSTablaTareas[iTSS].edx,	\
			stuTSSTablaTareas[iTSS].ebx,	\
			stuTSSTablaTareas[iTSS].ebx);
	vFnImprimir(	"\n esp:\t%d\t(0x%x)\tebp:\t%d\t(0x%x)",		\
			stuTSSTablaTareas[iTSS].esp,	\
			stuTSSTablaTareas[iTSS].esp,	\
			stuTSSTablaTareas[iTSS].ebp,	\
			stuTSSTablaTareas[iTSS].ebp);
	vFnImprimir(	"\n esi:\t%d\t(0x%x)\tedi:\t%d\t(0x%x)",		\
			stuTSSTablaTareas[iTSS].esi,	\
			stuTSSTablaTareas[iTSS].esi,	\
			stuTSSTablaTareas[iTSS].edi,	\
			stuTSSTablaTareas[iTSS].edi);
	vFnImprimir(	"\n es:\t%d\t(0x%x)\t  cs:\t%d\t(0x%x)",		\
			stuTSSTablaTareas[iTSS].es,	\
			stuTSSTablaTareas[iTSS].es,	\
			stuTSSTablaTareas[iTSS].cs,	\
			stuTSSTablaTareas[iTSS].cs);
	vFnImprimir(	"\n ss:\t%d\t(0x%x)\t  ds:\t%d\t(0x%x)",		\
			stuTSSTablaTareas[iTSS].ss,	\
			stuTSSTablaTareas[iTSS].ss,	\
			stuTSSTablaTareas[iTSS].ds,	\
			stuTSSTablaTareas[iTSS].ds);
	vFnImprimir(	"\n fs:\t%d\t(0x%x)\t  gs:\t%d\t(0x%x)",		\
			stuTSSTablaTareas[iTSS].fs,	\
			stuTSSTablaTareas[iTSS].fs,	\
			stuTSSTablaTareas[iTSS].gs,	\
			stuTSSTablaTareas[iTSS].gs);
	vFnImprimir(	"\n ldt:\t%d\t(0x%x)",				\
			stuTSSTablaTareas[iTSS].ldt,	\
			stuTSSTablaTareas[iTSS].ldt);
	vFnImprimir(	"\n trapbit:\t%d\t(0x%x)",			\
			stuTSSTablaTareas[iTSS].trapbit,	\
			stuTSSTablaTareas[iTSS].trapbit);
	vFnImprimir(	"\n uIOMapBase:\t%d\t(0x%x)",			\
			stuTSSTablaTareas[iTSS].uIOMapeoBase,	\
			stuTSSTablaTareas[iTSS].uIOMapeoBase);

	vFnImprimir ("\nReanudando Proceso %d", iPid);
	pstuPCB[iPCB].iEstado = iEstadoAnterior;
	vFnImprimirOk(55);
}


/**
\fn void vFnMenuBitmap()
\brief Muestra por pantalla el contenido del bitmap de memoria paginada
\date 09/04/2006
*/
void vFnMenuBitmap()
{
	vFnImprimirMapaBits();
}


/**
\fn void vFnMenuSegs()
\brief Muestra la posicion inicial y final de los segmentos de datos definidos para cada proceso
\date 25/10/2008
*/
void vFnMenuSegs()
{
    unsigned int i, uiNroSegmento;

    /**
    \note Ya que para SEGMENTACION no mantenemos ninguna estructura adicional
    para estadisticas de uso de memoria por procesos, generamos este informe
    consultando la tabla de PCBs.
    No vale la pena incluir este codigo en kernel/mem/memoria_s
    */

    vFnImprimir ("\n#### SEGMENTOS DE DATOS PARA CADA PROCESO ####");
    uiNroSegmento = 0;
    for(i=0 ; i < CANTMAXPROCS ; i++) {
        if( pstuPCB[i].iEstado != PROC_ELIMINADO &&
            pstuPCB[i].iEstado != PROC_NO_DEFINIDO) {
                uiNroSegmento++;

                vFnImprimir("\n#%3d %s PID=%3d PosGDT=%2d   ",
                        uiNroSegmento,
                        pstuPCB[i].stNombre,
                        pstuPCB[i].ulId,
                        pstuPCB[i].uiIndiceGDT_DS
                        );

                if( pstuPCB[i].uiIndiceGDT_DS == 2) {
                    vFnImprimir("(usa Segmento KERNEL 0 a 4Gb)");
                } else {
                    vFnImprimir("Inicio=0x%8x Fin=0x%8x Tam=%d",
                            pstuPCB[i].uiDirBase,
                            pstuPCB[i].uiDirBase + pstuPCB[i].uiLimite,
                            pstuPCB[i].uiLimite
                            );
                }
        }

        if ((uiNroSegmento % 14 == 0) && (uiNroSegmento > 0)) cFnPausa ();
    }

    //vFnListarBloquesLibres();
//	vFnMostrarMemoriaSegmentada();
}


/**
\fn void vFnMenuPag(int iPid)
\brief Muestra las pÃ¡ginas asignadas al proceso solicitado por lÃ­nea de
 comando.
\param iPid PID del proceso cuyas paginas se muestran
\date 09/04/2006
\modificado 08/08/2009
*/
void vFnMenuPag(int iPid)
{
	int iProcPos;

	if(uiModoMemoria!=MODOPAGINADO)
	{
		vFnImprimir("\nComando valido solo en modo paginado\n");
		return;
	}	

	vFnImprimir("\nPAGINAS POR PROCESOS:");
	vFnImprimir("El proceso %d posee los siguientes frames:\n", iPid);
	if ((iProcPos = iFnBuscaPosicionProc(iPid)) != -1)
		if (pstuPCB[iProcPos].iEstado != PROC_ELIMINADO)
			vFnImprimirTablaPaginas(pstuPCB
						[iProcPos].
						uiTamProc,
						pstuPCB
						[iProcPos].
						pstuTablaPaginacion);
		else vFnImprimir("El proceso no existe");
	else {
		vFnImprimir("Debe especificar un numero de proceso (PID)");
	}
}


/**
\brief Lanza un proceso de usuario a partir de un archivo ejecutable
\param iComandoPos PosiciÃ³n inicial del comando en el buffer de cCaracteres. Con esta informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la lÃ­nea de comandos.
\date 21/10/2008
*/
void vFnMenuEjecutar(int iArg1) {
	char stArg1[12];
    char * pstNombreArchivo;
    int iPosicion;
    int iStatus;
    long lRetorno;

	iFnCopiaCadena(stArg1, (char*)iArg1);

	if (stArg1[0] != '\0'){
        //Pasamos el nombre a mayusculas (cambiar si Sodium es case-sensitive)
        vFnStrUpr(stArg1);
        pstNombreArchivo = pstFnConcatenarCadena(stArg1,".BIN");

        //Creamos el proceso
        iPosicion = iFnCrearProceso( pstNombreArchivo,3,0 );
        ulPidProcesoForeground = pstuPCB[iPosicion].ulId;

        if(iPosicion < 0) {
            vFnImprimir("\nNo se pudo crear un proceso a partir de %s",
                    pstNombreArchivo);
            return;
        }

      //lRetorno = lFnSysWaitPid( ulPidProcesoForeground, &iStatus, 0 );

    }
}


/**
\fn void vFnMenuExec(int iArg1,iArg2)
\brief Lanza un proceso de sistema o de usuario y le reserva la cantidad
necesaria segÃºn el tamaÃ±o declarado por lÃ­nea de
comando. Si no hay espacio suficiente o no se pueden alocar mÃ¡s
procesos lo indicarÃ¡ con un mensaje de error.
\param iArg1 proceso de sistema o de usuario.
iArg2 tamaÃ±o del proceso
\date09/04/2006
\modificado 08/08/2009
*/
void vFnMenuExec(int iArg1, int iArg2)
{					
	if(uiModoMemoria==MODOPAGINADO)	
	{
		struct stuTablaPagina *pstuTablaPagina = 0;
		int indiceEnPcbs = -1;

		if ((iArg1 > 0) && (iArg1 < 3))
		{
			if ((iArg2 > 0) && (iArg2 < iTamanioMemoria * 8 * 4096))
			{
				vFnImprimir("\n Asignando memoria para un proceso de %d Bytes.",iArg2);
				pstuTablaPagina = pstuTablaPaginaFnAsignarPaginas(iArg2);
				if (pstuTablaPagina != 0)	//si habia memoria suficiente...
				{
					vFnImprimir("\nIniciando Proceso ... ");
					switch (iArg1)
					{
						case 1:
							indiceEnPcbs = iFnInstanciarReloj(iFnSistema,"PR_SISTEMA............");
							break;
						case 2:
							indiceEnPcbs = iFnInstanciarReloj(iFnProceso1,"PR_USUARIO............");
							break;
					}

					if (indiceEnPcbs != -1)
					{
						pstuPCB[indiceEnPcbs].uiTamProc = iArg2;
						pstuPCB[indiceEnPcbs].iPrioridad = iArg1;
						pstuPCB[indiceEnPcbs].pstuTablaPaginacion = pstuTablaPagina;
						vFnImprimir("[OK]");
					}
					else
					{
						vFnImprimir("\nEl sistema no acepta mas tareas, Limite = %d",CANTMAXPROCS);
						iFnLimpiarMemoria(iArg2,pstuTablaPagina);
						vFnImprimir("\nSe ha liberado la memoria reservada previamente");
					}
				}
				else
				{
					vFnImprimir("\nMemoria insuficiente para alocar el proceso");
				}
			}
			else
			{
				vFnImprimir("\nTamanio especificado no valido. Maximo = %d",iTamanioMemoria * 8 * 4096 - 1);
			}
		}
		else
		{
			vFnImprimir("\n Por favor ingrese 1 para lanzar un proceso de sistema o 2 para un proceso usuario");
		}
	} 
	else
	{
		int indiceEnPcbs = -1;
		int iValorRetorno;
	   	char * pcProceso;
	
        	if ( (iArg1 < 1) || (iArg1 > 2) )
		{
			vFnImprimir("\n Parametro invalido: Por favor ingrese: 1 para lanzar un proceso de sistema o 2 para un proceso usuario");
        	}
		else
		{
			if (iArg2 <= 0)
			{
				//Tamanio invalido
        	    		vFnImprimir("\n Tamanio de proceso invalido. Ingrese un valor superior.");
			}
			else
			{	
				//Parametros correctos; se intenta crear el segmento
	
				vFnImprimir("\n Creando un segmento de memoria para un proceso de %d bytes.", iArg2);
				//TODO - Sacar el pvFnKMalloc (pertenece al kernel)
        	    		pcProceso = (char *) pvFnReservarParticionUsuario( iArg2);
	
        	    		if (pcProceso == NULL)
				{
			                //No hay memoria para el segmento
			                vFnImprimir("\n No se pudo alojar el proceso. Tamanio solicitado: %d", iArg2);
				}	
				else
				{
        	        		//Se creo el segmento, ahora solo falta crear el proceso
        	        		vFnImprimir("\n Intentando iniciar Proceso...");
					switch (iArg1)
					{	
						case 1:     //Proceso de sistema
        	                			indiceEnPcbs=iFnInstanciarReloj(iFnSistema,"PR_SISTEMA...");
							break;
        	            			case 2:     //Proceso de usuario
        	                			indiceEnPcbs=iFnInstanciarReloj(iFnProceso1,"PR_USUARIO...");
				                        break;
						default:
							indiceEnPcbs = -2;
							vFnImprimir("\n Por favor ingrese 1 para lanzar un proceso de sistema o 2 para un proceso usuario");
							break;
					}	
        	        		if (indiceEnPcbs >= 0)
					{
						//Se pudo crear el proceso
        	            			/* Asignamos Tamanio, Prioridad y Direccion Base en el PCB
        	             			* del proceso creado.
        	             			* La direccion base solo la usara el comando kill para
        	             			* saber que bloque de memoria liberar con vFnKFree, ya que
        	             			* los procesos creados con iFnNuevaTareaEspecial usan como
        	             			* Stack parte de su TSS (espacio0, espacio1, etc).
        	             			*/
        	            			/* Se asigna manualmente uiTamProc, ya que por ser
        	             			* TAREA_ESPECIAL, iFnCrearPCB lo calcula 'mal' (toma el
        	             			* valor del tamano del segmento, el cual es 4Gb)
        	             			*/
        	            			pstuPCB[indiceEnPcbs].uiTamProc = iArg2;
        	            			pstuPCB[indiceEnPcbs].iPrioridad = iArg1;
	
        	            			pstuPCB[indiceEnPcbs].uiDirBase = (unsigned int) pcProceso;
	
        	            			vFnImprimir("[OK]");					
        	        		}
					else
					{
						if (indiceEnPcbs ==-1)
						{
        	            				//No se pudo crear el proceso, limite de tareas alcanzado
        	            				vFnImprimir("\n El sistema no acepta mas tareas, Limite = %d", CANTMAXPROCS);

        	            				//Se borra el segmento recien creado
        	            				vFnKFree(pcProceso);
        	            				vFnImprimir("\n Se ha liberado el segmento reservado");
						}
					}
				}	
			}		
		}
	}
}


/**
\fn void vFnMenuCheck(int iComandoPos)
\brief Comprueba que el nÃºmero de pÃ¡gina y offset sea vÃ¡lido para el
 proceso indicado. Se ingresan dichos parÃ¡metros por lÃ­nea de comandos.
\param iComandoPos PosiciÃ³n inicial del comando en el buffer de cCaracteres.
Con esta informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la
 lÃ­nea de comandos.
\date09/04/2006
*/
void vFnMenuCheck(int iComandoPos)
{
	char stArg1[16];
	char stArg2[16];
	char stArg3[16];
	int iArg1 = 0, iArg2 = 0, iArg3 = 0, iProcPos, iValorRetorno;
	if ((iFnGetArg(iComandoPos, 1, stArg1, 16) == 1)
	    && (iFnGetArg(iComandoPos, 2, stArg2, 16) == 1)
	    && (iFnGetArg(iComandoPos, 3, stArg3, 16) == 1)) {
		iArg1 = iFnCtoi(stArg1);
		iArg2 = iFnXtoi(stArg2);
		iArg3 = iFnXtoi(stArg3);
		if ((iProcPos = iFnBuscaPosicionProc(iArg1)) != -1) {
			if (iArg1 == 1) {
				vFnImprimir
				    ("\nEhh, no querrias quedarte sin shell...");
			} else {
				iValorRetorno =
				    iFnDarDireccion(pstuPCB
						    [iProcPos].
						    pstuTablaPaginacion,
						    pstuPCB
						    [iProcPos].
						    uiTamProc,
						    iArg2, iArg3);
				switch (iValorRetorno) {
				case -2:
					vFnImprimir
					    ("\nPagina Invalida, Pagina: %d",
					     iArg2);
					iFnLimpiarMemoria(pstuPCB
							  [iProcPos].
							  uiTamProc,
							  pstuPCB
							  [iProcPos].
							  pstuTablaPaginacion);
					pstuPCB[iProcPos].iEstado =
					    PROC_ELIMINADO;
					break;
				case -3:
					vFnImprimir
					    ("\nOffset Invalida, Offset: %d",
					     iArg3);
					iFnLimpiarMemoria(pstuPCB
							  [iProcPos].
							  uiTamProc,
							  pstuPCB
							  [iProcPos].
							  pstuTablaPaginacion);
					pstuPCB[iProcPos].iEstado =
					    PROC_ELIMINADO;
					break;
				default:
					vFnImprimir
					    ("\n Direccion Fisica:%x",
					     iValorRetorno);
				}
			}
		} else
			vFnImprimir("\nEl proceso no existe");
	}
}


/**
\fn void vFnMenuExecSeg(int iComandoPos)
\brief Lanza un proceso de sistema o de usuario y le reserva la cantidad
 necesaria segÃºn el tamaÃ±o declarado por lÃ­nea de
 comando. Si no hay espacio suficiente o no se pueden alocar mÃ¡s
 procesos lo indicarÃ¡ con un mensaje de error.
\param iComandoPos PosiciÃ³n inicial del comando en el buffer de cCaracteres.
Con esta informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la
 lÃ­nea de comandos.
\date 09/04/2006
*/
void vFnMenuExecSeg(int iArg1, int iArg2)
{	
			//1
	//char stArg1[16];
	//char stArg2[16];
	//int iArg1 = 0;
	int indiceEnPcbs = -1;
	//int iArg2 = 0;
	int iValorRetorno;
    char * pcProceso;
	/*if ((iFnGetArg(iComandoPos, 1, stArg1, 16) == 1)
	    && (iFnGetArg(iComandoPos, 2, stArg2, 16) == 1)) {	//2
		iArg1 = iFnCtoi(stArg1);    //Tipo de proceso (SISTEMA/USUARIO)
		iArg2 = iFnCtoi(stArg2);	//tamanio en bytes del proceso.*/
        if ( (iArg1 < 1) || (iArg1 > 2) ) {
            vFnImprimir("\n Parametro invalido: Por favor ingrese: "
                        "1 para lanzar un proceso de sistema o "
                        "2 para un proceso usuario");
        } else if (iArg2 <= 0) {
            //Tamanio invalido
            vFnImprimir("\n Tamanio de proceso invalido. "
                        "Ingrese un valor superior.");
/*		if ((iArg2 <= 0) || (iArg2 > iFnSegmentoMaximo())) {
			vFnImprimir
			    ("\nTamanio de proceso invalido. Ingrese un valor entre [1 y %d]",
			     iFnSegmentoMaximo());*/
		} else {	//3
            //Parametros correctos; se intenta crear el segmento
/*			iValorRetorno = iFnMalloc(iArg2);
			if (iValorRetorno == -1) {	//4
				vFnImprimir
				    ("\nNo se pudo alocar el proceso. Tamanio solocitado: %d",
				     iArg2);*/
            vFnImprimir("\n Creando un segmento de memoria para un proceso de "
                        "%d bytes.", iArg2);
            //TODO - Sacar el pvFnKMalloc (pertenece al kernel)
            pcProceso = (char *) pvFnReservarParticionUsuario( iArg2 );

            if (pcProceso == NULL) {
                //No hay memoria para el segmento
                vFnImprimir("\n No se pudo alojar el proceso. "
                            "Tamanio solicitado: %d", iArg2);
			}	//4
			else {	//5
                //Se creo el segmento, ahora solo falta crear el proceso
/*				vFnImprimir
				    ("\n Asignando memoria para un proceso de %d Bytes.",
				     iArg2);*/
                vFnImprimir("\n Intentando iniciar Proceso...");
				switch (iArg1) {	//6
                    case 1:     //Proceso de sistema
                        indiceEnPcbs=iFnInstanciarReloj(
                                                   iFnSistema,"PR_SISTEMA...");
					break;
                    case 2:     //Proceso de usuario
                        indiceEnPcbs=iFnInstanciarReloj(
                                                   iFnProceso1,"PR_USUARIO...");
                        break;
				default:
					indiceEnPcbs = -2;
					vFnImprimir
					    ("\n Por favor ingrese 1 para lanzar un proceso de sistema o 2 para un proceso usuario");
					break;
				}	//6
                if (indiceEnPcbs >= 0) {
                    //Se pudo crear el proceso
                    /* Asignamos Tamanio, Prioridad y Direccion Base en el PCB
                     * del proceso creado.
                     * La direccion base solo la usara el comando kill para
                     * saber que bloque de memoria liberar con vFnKFree, ya que
                     * los procesos creados con iFnNuevaTareaEspecial usan como
                     * Stack parte de su TSS (espacio0, espacio1, etc).
                     */
                    /* Se asigna manualmente uiTamProc, ya que por ser
                     * TAREA_ESPECIAL, iFnCrearPCB lo calcula 'mal' (toma el
                     * valor del tamano del segmento, el cual es 4Gb)
                     */
                    pstuPCB[indiceEnPcbs].uiTamProc = iArg2;
                    pstuPCB[indiceEnPcbs].iPrioridad = iArg1;
/*					pstuPCB[indiceEnPcbs].
					    uiDirBase = iValorRetorno;*/
                    pstuPCB[indiceEnPcbs].uiDirBase = (unsigned int) pcProceso;

                    vFnImprimir("[OK]");
					//5
                } else if (indiceEnPcbs ==-1) {
                    //No se pudo crear el proceso, limite de tareas alcanzado
                    vFnImprimir("\n El sistema no acepta mas tareas, "
                                "Limite = %d", CANTMAXPROCS);

                    //Se borra el segmento recien creado
                    vFnKFree(pcProceso);
                    vFnImprimir("\n Se ha liberado el segmento reservado");
				}
			}	//5
		}		//3
	/*}			//2
	else {			//9
		vFnImprimir
		    ("\nError, argumento(s) incorrecto(s).\nForma de uso: Cmd>exec [1 o 2] [tamanio en Kb del proceso]");
	}*/			//9
}				//1





/**
\fn void vFnMenuSumaFpu(int iArg1, int iArg2)
\brief Realiza la suma de dos numeros en formato de punto flotante usando la FPU
\param iComandoPos PosiciÃ³n inicial del comando en el buffer de cCaracteres.
 Con esta informaciÃ³n se podrÃ¡n recuperar los parÃ¡metros pasados desde la
 lÃ­nea de comandos.
\date 10/06/2008
*/
void vFnMenuSumaFpu(int iArg1, int iArg2)
{
	char strArg1[127];	//512];
	char strArg2[127];	//512];
/*	float fArg1;
	float fArg2;
*/
double fArg1,fArg2;

	iFnCopiaCadena(strArg1, (char*)iArg1);
	iFnCopiaCadena(strArg2, (char*)iArg2);

	if (strArg1[0] != '\0' && strArg2[0] != '\0') {
		fArg1 = fFnAtof(strArg1);
		fArg2 = fFnAtof(strArg2);
		/*fArg1 = 2.1;
		fArg2 = 2.2;
		float fAux;
		fAux = fArg1 + fArg2;*/
		vFnImprimir("\n%f + %f = %f", fArg1, fArg2, fArg1+fArg2);
                while(1);
	} else {
		vFnSysSetearColor(HWND_COMANDO, BLANCO_BRILLANTE);
		vFnImprimir("\nAyuda del comando sumafpu:\n");
		vFnSysSetearColor(HWND_COMANDO, BLANCO);
		vFnImprimir("Forma de uso: Cmd>sumafpu NUMERO1 NUMERO2");
	}
}



/**
\fn void vFnTermLog(unsigned char ucCaracter)
\brief procesa el caracter ingresado al teclado para realizar algo en la "terminal" log..
\param  ucCaracter Caracter leido desde el teclado.
\date 05/06/2006
*/
void vFnTermLog(unsigned char ucCaracter)
{
	switch (ucCaracter) {
	case TECLA_ARR:
	case '8':
		vFnLogScrollArriba();
		break;
	case TECLA_ABA:
	case '2':
		vFnLogScrollAbajo();
		break;
	case '9':
		vFnLogScrollMaximo();
		break;
	case '3':
	case TECLA_ENTER:
		vFnLogScrollMinimo();
		break;
	case 'b':
	case 'B':
		vFnLogBorrar();
		break;
	}
}
//************************** Grupo 4 Inicio *************************************/

/**
 * @brief Instancia el diskette
 * @date 04/08/2008
 */
void vFnMenuFd()
{
	iFnIniciarFatDrv();
}


void 
vFnAPM_info(int iComandoPos)
{
   vFnImprimir("\nAPM Installation Check:");
   vFnImprimir("\n   AX: 0x%x", uiAPM_check_ax);
   vFnImprimir("\n   BX: 0x%x", uiAPM_check_bx);
   vFnImprimir("\n   CX: 0x%x", uiAPM_check_cx);
   
   vFnImprimir("\nAPM Protected Mode 32-bit Interface:");
   vFnImprimir("\n   32-bit Code Segment: 0x%x", uiAPM_32_cs);
   vFnImprimir("\n   16-bit Code Segment: 0x%x", uiAPM_16_cs);
   vFnImprimir("\n   Offset Entry Point: 0x%x", uiAPM_offset_entry_point);
   vFnImprimir("\n   Data Segment: 0x%x", uiAPM_ds);

   if ( 0x7000 == uiAPM_ds )     //ds fue remapeado
      vFnImprimir(" \(w\/ remap memoria\)");
}

void
vFnAPM_shutdown(int iComandoPos)
{
   if ( 1 == uiAPM_ok )
   {
      vFnImprimir("\nShutdown w/ APM 1.2 ...");
	   fShutdown();
   }
   
   // Tuvimos algun error al establecer la conexion en modo real
   vFnImprimir("\nError en conexion APM PM 32-bit ...");
   vFnImprimir("\nPara informacion detallada consulte comando \"apminfo\"");
}
